local EmoTalentUtil = require "packages.emopack.pkg.emopack_talent.util" -- 加载战法核心
local skel = require "packages.emopack.pkg.emopack_talent.talents.core" ---@type SkillSkeleton

local hasTalent = EmoTalentUtil.hasTalent
local logTalent = EmoTalentUtil.logTalent
local invokeTalent = EmoTalentUtil.invokeTalent
local discoverTalent = EmoTalentUtil.discoverTalent
local removeTalent = EmoTalentUtil.removeTalent
local handleInvokedTalents = EmoTalentUtil.handleInvokedTalents
local getDynValue = EmoTalentUtil.getDynValue
local addDynValue = EmoTalentUtil.addDynValue
local timesCheckFilter = EmoTalentUtil.timesCheckFilter
local timesCheck = EmoTalentUtil.timesCheck



-- 关于濒死、死亡事件的战法

--- 进入濒死时
skel:addEffect(fk.EnterDying, {
  mute = true,
  is_delay_effect = true,
  can_trigger = function (self, event, target, player, data)
    local cost_data = {}
    if target == player then -- 我进入濒死
      if hasTalent(player, "emot_ganlin") and not player.dead -- 甘霖
      and player:isWounded() and player:getMark("emot_ganlin") == 0 then
        table.insert(cost_data, "emot_ganlin")
      end
      for _, t in ipairs({"emot_xianji", "emot_jinshuhua", "emot_genshen"}) do -- 献祭、金属化、根深蒂固
        if hasTalent(player, t) then
          table.insert(cost_data, t)
        end
      end
    end
    if hasTalent(player, "emot_houzi") and player:isEnemy(target) and not target.dead -- 猴子偷桃
     and not player.dead then
      table.insert(cost_data, "emot_houzi")
    end
    if hasTalent(player, "emot_daoshi") and not player.dead then -- 道士
      table.insert(cost_data, "emot_daoshi")
    end
    if timesCheckFilter(cost_data, player) then
      event:setCostData(self, cost_data)
      return true
    end
  end,
  on_use = function(self, event, target, player, data)
    local room = player.room
    local cost_data = event:getCostData(self) or {}
    if table.contains(cost_data, "emot_daoshi") and not player.dead and timesCheck(player, "emot_daoshi") then -- 道士
      invokeTalent(player, "emot_daoshi", event)
      local judge = {
        who = player,
        reason = "emot_daoshi",
        pattern = ".|.|^nosuit",
      }
      room:judge(judge)
      if judge.card and judge.card.color ~= Card.NoColor then
        local style = judge.card.color == Card.Red and "faith" or "demon"
        discoverTalent(player, { style = style, random = true })
      end
    end
    if table.contains(cost_data, "emot_jinshuhua") then -- 金属化
      invokeTalent(player, "emot_jinshuhua", event)
      room:changeShield(player, 5)
    end
    if table.contains(cost_data, "emot_ganlin") and player:isWounded() and player:getMark("emot_ganlin") == 0 then -- 甘霖
      invokeTalent(player, "emot_ganlin", event)
      room:setPlayerMark(player, "emot_ganlin", 1)
      room:recover { num = player.maxHp - player.hp, skillName = skel.name, who = player, recoverBy = player }
    end
    if table.contains(cost_data, "emot_houzi") and not player.dead then -- 猴子偷桃
      local cards = table.filter(target:getCardIds("he"), function(id)
        return Fk:getCardById(id).trueName == "peach"
      end)
      if #cards > 0 then
        invokeTalent(player, "emot_houzi", event)
        room:obtainCard(player, cards, true, fk.ReasonPrey, player, skel.name)
        if not target.dead then
          target:drawCards(#cards, skel.name)
        end
      end
    end
    if table.contains(cost_data, "emot_xianji") then -- 献祭
      invokeTalent(player, "emot_xianji", event)
      local max = 0
      for _, p in ipairs(room.alive_players) do
        if player:isEnemy(p) then
          max = math.max(max, p:getHandcardNum())
        end
      end
      local targets = table.filter(room:getAlivePlayers(), function(p)
        return player:isEnemy(p) and p:getHandcardNum() == max
      end)
      for _, p in ipairs(targets) do
        local cards = table.filter(p:getCardIds("he"), function(id)
          return not p:prohibitDiscard(id)
        end)
        if #cards > 0 then
          room:throwCard(cards, skel.name, p, p)
          local hearts = #table.filter(cards, function(id)
            return Fk:getCardById(id).suit == Card.Heart
          end)
          if hearts > 0 and not player.dead then
            room:recover { num = hearts, skillName = skel.name, who = player, recoverBy = player }
          end
        end
      end
    end
    if table.contains(cost_data, "emot_genshen") and not player.dead then -- 根深蒂固，晚点结算
      while player.hp < 1 and not player.dead and not player:isKongcheng() do
        local hearts = table.filter(player:getCardIds("h"), function(id)
          return Fk:getCardById(id).suit == Card.Heart
        end)
        if #hearts == 0 then break end
        invokeTalent(player, "emot_genshen", event)
        local peach = Fk:cloneCard("peach")
        peach:addSubcard(table.random(hearts))
        peach.skillName = "emot_genshen"
        room:useCard{
          from = player, tos = {player}, card = peach,
        }
      end
    end
    handleInvokedTalents(player, event)
  end,
})

--- 脱离濒死时
skel:addEffect(fk.AfterDying, {
  mute = true,
  is_delay_effect = true,
  can_trigger = function (self, event, target, player, data)
    local cost_data = {}
    if hasTalent(player, "emot_wushi") and not player.dead and player:isEnemy(target) and not target.dead -- 武士
     and target:getMark("emot_wushi-turn") == 0 then
      table.insert(cost_data, "emot_wushi")
    end
    if target == player and not player.dead then
      if hasTalent(player, "emot_due") then -- 毒蛾
        table.insert(cost_data, "emot_due")
      end
    end
    if timesCheckFilter(cost_data, player) then
      event:setCostData(self, cost_data)
      return true
    end
  end,
  on_use = function(self, event, target, player, data)
    local room = player.room
    local cost_data = event:getCostData(self) or {}
    if table.contains(cost_data, "emot_wushi") and not target.dead then -- 武士
      invokeTalent(player, "emot_wushi", event)
      room:setPlayerMark(target, "emot_wushi-turn", 1) -- 偷懒
      room:useVirtualCard("fire__slash", nil, player, target, skel.name, true)
      room:setPlayerMark(target, "emot_wushi-turn", 0)
    end
    if table.contains(cost_data, "emot_due") then -- 毒蛾
      local targets = table.filter(room.alive_players, function(p)
        return player:isEnemy(p) and p.hp > 1
      end)
      if #targets > 0 then
        invokeTalent(player, "emot_due", event)
        local to = table.random(targets)
        room:doIndicate(player, {to})
        room:delay(150)
        room:loseHp(to, to.hp - 1, skel.name)
      end
    end
    handleInvokedTalents(player, event)
  end,
})

--- 死亡时（此时未进行死亡弃牌、清除标记）
skel:addEffect(fk.Death, {
  mute = true,
  is_delay_effect = true,
  can_trigger = function (self, event, target, player, data)
    local cost_data = {}
    local room = player.room
    local current = room:getCurrent()
    if hasTalent(player, "emot_qiyi") and target.role == "loyalist" and data.killer == player and not player.dead then -- 起义军
      table.insert(cost_data, "emot_qiyi")
    end
    if hasTalent(player, "emot_zhankuang") and data.killer == player and not player.dead then -- 战狂
      table.insert(cost_data, "emot_zhankuang")
    end
    if hasTalent(player, "emot_tujiu") and data.killer ~= player and not player.dead then -- 秃鹫
      table.insert(cost_data, "emot_tujiu")
    end
    if hasTalent(player, "emot_xuezuan") and not player.dead and target ~= player then -- 血钻
      table.insert(cost_data, "emot_xuezuan")
    end
    if hasTalent(player, "emot_zuojian") and target:getMark("emot_zuojian") ~= 0 and not player.dead then -- 作茧自缚
      table.insert(cost_data, "emot_zuojian")
    end
    if not table.contains({"wei", "shu", "wu"}, target.kingdom) then -- 三分天下
      if current and hasTalent(player, "emot_sanfen") and player:isFriend(current) and player:isEnemy(target) then
        table.insert(cost_data, "emot_sanfen")
      end
    else -- 三国归晋
      if current and hasTalent(player, "emot_guijin") and player:isFriend(current) and player:isEnemy(target) then
        table.insert(cost_data, "emot_guijin")
      end
    end
    if timesCheckFilter(cost_data, player) then
      event:setCostData(self, cost_data)
      return true
    end
  end,
  on_use = function(self, event, target, player, data)
    local cost_data = event:getCostData(self) or {}
    local room = player.room
    if table.contains(cost_data, "emot_xuezuan") and not player.dead then -- 血钻
      local num = #target:getSkillNameList()
      if num > 0 then
        invokeTalent(player, "emot_xuezuan", event)
        EmoTalentUtil:addMoney(player, num * 10)
      end
    end
    if table.contains(cost_data, "emot_qiyi") and not player.dead then -- 起义军
      invokeTalent(player, "emot_qiyi", event)
      player:drawCards(5, skel.name)
    end
    if table.contains(cost_data, "emot_zhankuang") and not player.dead then -- 战狂
      invokeTalent(player, "emot_zhankuang", event)
      discoverTalent(player, { rarity_limit = {2, 3} })
    end
    if table.contains(cost_data, "emot_zuojian") and not player.dead then -- 作茧自缚（获得战法）
      invokeTalent(player, "emot_zuojian", event)
      discoverTalent(player)
    end
    if table.contains(cost_data, "emot_tujiu") and not player.dead then -- 秃鹫
      local skills = table.filter(target:getSkillNameList(), function(s)
        return Fk.skills[s] and not Fk.skills[s]:hasTag(Skill.Permanent)
        and not player:hasSkill(s, true)
      end)
      if #skills > 0 then
        invokeTalent(player, "emot_tujiu", event)
        room:handleAddLoseSkills(player, table.random(skills))
      end
    end
    if table.contains(cost_data, "emot_sanfen") then -- 三分天下
      local current = room:getCurrent()
      local three = {"wei", "shu", "wu"}
      if current and not current.dead then
        invokeTalent(player, "emot_sanfen", event)
        local skills = {}
        for _, g in ipairs(Fk:getAllGenerals()) do
          if table.contains(three, g.kingdom) and (g.subkingdom == nil or table.contains(three, g.subkingdom)) then
            for _, s in ipairs(g:getSkillNameList(true)) do
              if not Fk.skills[s]:hasTag(Skill.AttachedKingdom) and not current:hasSkill(s, true) then
                table.insert(skills, s)
              end
            end
          end
        end
        if #skills > 0 then
          room:handleAddLoseSkills(current, table.random(skills))
        end
      end
    end
    if table.contains(cost_data, "emot_guijin") then -- 三国归晋
      local current = room:getCurrent()
      if current and not current.dead then
        invokeTalent(player, "emot_guijin", event)
        local skills = {}
        for _, g in ipairs(Fk:getAllGenerals()) do
          if table.contains({"qun", "jin"}, g.kingdom) then
            for _, s in ipairs(g:getSkillNameList(true)) do
              if not Fk.skills[s]:hasTag(Skill.AttachedKingdom) and not current:hasSkill(s, true) then
                table.insert(skills, s)
              end
            end
          end
        end
        if #skills > 0 then
          room:handleAddLoseSkills(current, table.random(skills))
        end
      end
    end
    handleInvokedTalents(player, event)
  end,
})

--- 死亡后
skel:addEffect(fk.Deathed, {
  mute = true,
  is_delay_effect = true,
  can_trigger = function (self, event, target, player, data)
    local cost_data = {}
    local room = player.room
    if hasTalent(player, "emot_qiufeng") and player:isEnemy(target) and not player.dead then -- 秋风扫叶
      table.insert(cost_data, "emot_qiufeng")
    end
    if timesCheckFilter(cost_data, player) then
      event:setCostData(self, cost_data)
      return true
    end
  end,
  on_use = function(self, event, target, player, data)
    local cost_data = event:getCostData(self) or {}
    local room = player.room
    if table.contains(cost_data, "emot_qiufeng") and not player.dead then -- 秋风扫叶
      local to
      local temp = target
      repeat
        temp = temp.next
        if not temp.dead and player:isEnemy(temp) then
          to = temp
          break
        end
      until temp == target
      if to then
        invokeTalent(player, "emot_qiufeng", event)
        local num = getDynValue(player, "emot_qiufeng")
        addDynValue(player, "emot_qiufeng")
        room:doIndicate(player, {to})
        room:delay(150)
        room:damage { from = player, to = to, damage = num, skillName = skel.name }
      end
    end
    handleInvokedTalents(player, event)
  end,
})

--- 处于濒死状态时（求桃）
skel:addEffect(fk.AskForPeaches, {
  mute = true,
  is_delay_effect = true,
  priority = 10, -- 仅用于韧牛掐断濒死求桃
  can_trigger = function (self, event, target, player, data)
    local who = data.who
    return who and hasTalent(who, "emot_renniu") and who ~= player.room.current and not who.dead and who.dying
  end,
  on_use = function(self, event, target, player, data)
    logTalent(data.who, "emot_renniu")
    data.ignoreDeath = true
    return true -- 掐断询问，别继续求桃
  end,
})

--- 濒死状态求桃结束后（濒死失救）
skel:addEffect(fk.AskForPeachesDone, {
  mute = true,
  is_delay_effect = true,
  can_trigger = function (self, event, target, player, data)
    local cost_data = {}
    if target == player then
      if not player.dead and player.hp < 1 and not data.ignoreDeath then -- 濒死失救
       -- 救赎，夺舍，新生，重启，风暴眼，魔力护盾，丹书铁券
        for _, t in ipairs({"emot_jiushu", "emot_duoshe", "emot_xinsheng", "emot_chongqi",
         "emot_stormeye", "emot_modun", "emot_tiequan"}) do
          if hasTalent(player, t) then
            table.insert(cost_data, t)
          end
        end
      end
    end
    if timesCheckFilter(cost_data, player) then
      event:setCostData(self, cost_data)
      return true
    end
  end,
  on_use = function(self, event, target, player, data)
    local room = player.room
    local cost_data = event:getCostData(self) or {}
    if table.contains(cost_data, "emot_tiequan") and not player.dead and player.hp < 1 then -- 丹书铁券
      invokeTalent(player, "emot_tiequan", event)
      removeTalent(player, "emot_tiequan")
      room:recover { num = player.maxHp - player.hp, skillName = skel.name, who = player, recoverBy = player }
      EmoTalentUtil:addMoney(player, 50)
    end
    if table.contains(cost_data, "emot_jiushu") and not player.dead and player.hp < 1 then -- 救赎
      invokeTalent(player, "emot_jiushu", event)
      removeTalent(player, "emot_jiushu")
      room:changeMaxHp(player, 3)
      if not player.dead then
        room:recover { num = player.maxHp - player.hp, skillName = skel.name, who = player, recoverBy = player }
      end
    end
    if table.contains(cost_data, "emot_duoshe") and not player.dead and player.hp < 1 then -- 夺舍
      local targets = table.filter(room.alive_players, function(to) -- 只要体力值大于我的敌方
        return player:isEnemy(to) and to.hp > player.hp
      end)
      if #targets > 0 then
        invokeTalent(player, "emot_duoshe", event)
        removeTalent(player, "emot_duoshe")
        local max = player.hp
        for _, to in ipairs(targets) do
          max = math.max(max, to.hp)
        end
        targets = table.filter(targets, function(to) return to.hp == max end)
        local to = table.random(targets)
        room:doIndicate(player, {to})
        room:delay(150)
        local toHp, myHp = to.hp, player.hp
        -- 强制修改体力值，绕开触发事件
        room:setPlayerProperty(player, "hp", toHp)
        if player.hp > player.maxHp then
          room:setPlayerProperty(player, "maxHp", toHp)
        end
        if player.hp > 0 and player.dying then
          room:setPlayerProperty(player, "dying", false)
        end
        room:sendLog{
          type = "#ShowHPAndMaxHP",
          from = player.id,
          arg = player.hp,
          arg2 = player.maxHp,
        }
        if not to.dead then
          room:changeHp(to, myHp - to.hp, nil, skel.name) -- 这个方法可以正常触发濒死
        end
      end
    end
    if table.contains(cost_data, "emot_modun") and not player.dead and player.hp < 1 then -- 魔力护盾
      invokeTalent(player, "emot_modun", event)
      removeTalent(player, "emot_modun")
      room:setPlayerMark(player, "emot_modun-turn", 1)
      room:recover { num = player.maxHp - player.hp, skillName = skel.name, who = player, recoverBy = player }
    end
    if table.contains(cost_data, "emot_xinsheng") and not player.dead and player.hp < 1 then -- 新生
      invokeTalent(player, "emot_xinsheng", event)
      removeTalent(player, "emot_xinsheng")
      room:recover { num = player.maxHp - player.hp, skillName = skel.name, who = player, recoverBy = player }
      if not player.dead then
        discoverTalent(player, { exclude = {"emot_xinsheng"}, style = "nature" })
      end
    end
    if table.contains(cost_data, "emot_chongqi") and not player.dead and player.hp < 1 then -- 重启
      invokeTalent(player, "emot_chongqi", event)
      removeTalent(player, "emot_chongqi")
      player:gainAnExtraTurn(true, skel.name)
      room:recover { num = player.maxHp - player.hp, skillName = skel.name, who = player, recoverBy = player }
      EmoTalentUtil.breakTurn(room)
    end
    if table.contains(cost_data, "emot_stormeye") and not player.dead and player.hp < 1 then -- 风暴眼
      invokeTalent(player, "emot_stormeye", event)
      removeTalent(player, "emot_stormeye")
      room:recover { num = player.maxHp - player.hp, skillName = skel.name, who = player, recoverBy = player }
      for _, to in ipairs(room:getAlivePlayers()) do
        if player:isEnemy(to) and not to.dead then
          room:delay(150)
          room:damage { from = player, to = to, damage = 3, skillName = skel.name }
        end
      end
    end
    handleInvokedTalents(player, event)
  end,
})

-- 死亡刷新系列
skel:addEffect(fk.Death, {
  can_refresh = function (self, event, target, player, data)
    return true
  end,
  on_refresh = function (self, event, target, player, data)
    local room = player.room
    room:setPlayerMark(player, "emot_relie", 0)
    room:setPlayerMark(player, "emot_ganlin", 0)
  end,
})

-- 复活时恢复战法
skel:addEffect(fk.AfterPlayerRevived, {
  can_refresh = function (self, event, target, player, data)
    return target == player
  end,
  on_refresh = function (self, event, target, player, data)
    EmoTalentUtil:attachTalent(player)
  end,
})


